`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: CBICR, Tsinghua Univ.
// Engineer: Hongyi Li & Kimi & Deepseek
// 
// Create Date: 2025/03/16 20:25
// Design Name: 
// Module Name: BF16 Basic ALU
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////

module bfloat16_Multiplier(
    input [15:0] A,B,
    output reg [15:0]prod,
    output reg ov1
);
    
    wire [6:0]s1,s2;
    wire [7:0]e1,e2;
    wire [13:0]s;
    wire sign;
    wire [7:0]e;
    
    
    assign s1=A[6:0];
    assign s2=B[6:0];
    
    assign e1=A[14:7];
    assign e2=B[14:7];
    
    assign e=e1+e2-127;
    assign s=s1*s2;
    assign sign=A[15]^B[15];
    
    always@(*)
    begin
    if(e1+e2>382 || e1+e2<127)
        ov1=1'b1;
    else
        ov1=1'b0;
    end
    
    always@(*)
    begin
        if(ov1==1) 
            prod=16'b0;
        else
            prod={sign,e,s[13:7]};
    end
    
endmodule

module bf16_multiplier (
    input  [15:0] a,      // BF16 input A
    input  [15:0] b,      // BF16 input B
    output [15:0] product // BF16 output product
);
    bfloat16_Multiplier uut(
        .A(a),
        .B(b),
        .prod(product),
        .ov1()
    );
endmodule

module bf16_adder (
    input  [15:0] a,      // BF16 input A
    input  [15:0] b,      // BF16 input B
    output [15:0] sum     // BF16 output sum
);

    // Extract sign, exponent, and mantissa for input A
    wire sign_a = a[15];
    wire [7:0] exponent_a = a[14:7];
    wire [6:0] mantissa_a = a[6:0];

    // Extract sign, exponent, and mantissa for input B
    wire sign_b = b[15];
    wire [7:0] exponent_b = b[14:7];
    wire [6:0] mantissa_b = b[6:0];

    // Calculate the absolute difference between exponents
    wire [7:0] exp_diff = (exponent_a > exponent_b) ? (exponent_a - exponent_b) : (exponent_b - exponent_a);

    // Align mantissas based on exponent difference
    wire [7:0] aligned_mantissa_a = (exponent_a > exponent_b) ? {1'b1, mantissa_a} : {1'b1, mantissa_a} >> (exp_diff > 7 ? 7 : exp_diff);
    wire [7:0] aligned_mantissa_b = (exponent_b > exponent_a) ? {1'b1, mantissa_b} : {1'b1, mantissa_b} >> (exp_diff > 7 ? 7 : exp_diff);

    // Determine the larger exponent for the result
    wire [7:0] result_exponent = (exponent_a > exponent_b) ? exponent_a : exponent_b;

    // Add the aligned mantissas
    wire [8:0] mantissa_sum;
    assign mantissa_sum = (sign_a == sign_b) ? 
                          ({1'b0, aligned_mantissa_a} + {1'b0, aligned_mantissa_b}) : 
                          (sign_a ? ({1'b0, aligned_mantissa_a} - {1'b0, aligned_mantissa_b}) : 
                                    ({1'b0, aligned_mantissa_b} - {1'b0, aligned_mantissa_a}));

    // Normalize the result
    wire [7:0] normalized_mantissa;
    wire [7:0] normalized_exponent;
    wire result_sign;

    assign normalized_mantissa = mantissa_sum[8] ? mantissa_sum[8:1] : mantissa_sum[7:0];
    assign normalized_exponent = mantissa_sum[8] ? result_exponent + 1 : result_exponent;
    assign result_sign = (sign_a == sign_b) ? sign_a : (mantissa_sum[8] ? sign_a : sign_b);

    // Round the mantissa (simple truncation for this example)
    wire [6:0] rounded_mantissa = normalized_mantissa[7:1];

    // Combine sign, exponent, and mantissa to form the final result
    assign sum = {result_sign, normalized_exponent, rounded_mantissa};

endmodule

module bf16_divider (
    input [15:0] a,      // BF16 input A (dividend)
    input [15:0] b,      // BF16 input B (divisor)
    output reg [15:0] quotient // BF16 output quotient (a / b)
);

    // BF16 format:
    // [15]    : Sign bit
    // [14:10] : Exponent (5 bits)
    // [9:0]   : Mantissa (10 bits)

    // Intermediate signals for unpacking and processing
    reg sign_a, sign_b, sign_result;
    reg [4:0] exp_a, exp_b, exp_result;
    reg [9:0] mantissa_a, mantissa_b, mantissa_result;

    // Normalize mantissa and adjust exponent
    reg [9:0] normalized_mantissa_a, normalized_mantissa_b;
    reg [4:0] adjusted_exp_a, adjusted_exp_b;

    // Temporary signals for division
    reg [19:0] extended_mantissa_a, extended_mantissa_b;
    reg [19:0] temp_result;

    // Unpack inputs
    always @(*) begin
        // Extract sign bits
        sign_a = a[15];
        sign_b = b[15];

        // Extract exponents
        exp_a = a[14:10];
        exp_b = b[14:10];

        // Extract mantissas
        mantissa_a = a[9:0];
        mantissa_b = b[9:0];

        // Normalize mantissas
        if (exp_a != 5'b00000) begin
            normalized_mantissa_a = {1'b1, mantissa_a};
            adjusted_exp_a = exp_a;
        end else begin
            normalized_mantissa_a = {1'b0, mantissa_a};
            adjusted_exp_a = 5'b00000;
        end

        if (exp_b != 5'b00000) begin
            normalized_mantissa_b = {1'b1, mantissa_b};
            adjusted_exp_b = exp_b;
        end else begin
            normalized_mantissa_b = {1'b0, mantissa_b};
            adjusted_exp_b = 5'b00000;
        end

        // Calculate result sign
        sign_result = sign_a ^ sign_b;

        // Calculate result exponent
        exp_result = adjusted_exp_a - adjusted_exp_b + 5'd15;

        // Perform mantissa division using extended precision
        extended_mantissa_a = {normalized_mantissa_a, 10'b0};
        extended_mantissa_b = {normalized_mantissa_b, 10'b0};
        temp_result = extended_mantissa_a / extended_mantissa_b;

        // Normalize result mantissa
        mantissa_result = temp_result[19:10];

        // Pack result into BF16 format
        quotient = {sign_result, exp_result, mantissa_result};
    end

endmodule